﻿using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Collections.Generic;
using System.Linq;
using Workbench.Models;
using Workbench.Operations;
using Workbench.Shared;

namespace WorkbenchTests
{
    [TestClass]
    public class ProjectOperationsTests
    {
        [TestInitialize]
        public void Setup()
        {
            TestUtility.CreateAndInitializeTempDatabase();
        }

        [TestMethod]
        public void ProjectOperationsTests_can_save_and_load_model()
        {
            var createdRoot = ProjectOperations.GetRootDirectory();
            var createdDir = ProjectOperations.AddDirectory("Romani", createdRoot.RowId);
            var fileName = TestUtility.CreateTempFileWithText("Imalo Edno vreme");
            var createdFile = ProjectOperations.AddExistingFile(fileName, createdDir.RowId);

            var readRoot = ProjectOperations.GetRootDirectory();
            Assert.IsTrue(createdRoot.Equals(readRoot));
            Assert.AreEqual(1, readRoot.Children.Count);
            Assert.IsInstanceOfType(readRoot.Children[0], typeof(ProjectDirectoryModel));
            var readDir = readRoot.Children[0] as ProjectDirectoryModel;
            Assert.IsTrue(createdDir.Equals(readDir));
            Assert.AreEqual(1, readDir.Children.Count);
            Assert.IsInstanceOfType(readDir.Children[0], typeof(ProjectFileModel));
            var readFile = readDir.Children[0] as ProjectFileModel;
            Assert.IsTrue(createdFile.Equals(readFile));
        }

        [TestMethod]
        public void ProjectOperationsTests_delete_of_file_clears_dependant_words_sentences_and_paragraphs()
        {
            var rootDir = ProjectOperations.GetRootDirectory();
            var measures = ProjectOperations.GetQuantitativeMeasures(rootDir.GetContextIncludedFiles());
            Assert.AreEqual(0, measures.TextLengthInRunningWords);
            Assert.AreEqual(0, measures.Paragraphs);
            Assert.AreEqual(0, measures.Sentences);

            var fileName = TestUtility.CreateTempFileWithText("abra kadabra.");
            var file = ProjectOperations.AddExistingFile(fileName, rootDir.RowId);

            rootDir = ProjectOperations.GetRootDirectory();
            measures = ProjectOperations.GetQuantitativeMeasures(rootDir.GetContextIncludedFiles());
            Assert.AreEqual(2, measures.TextLengthInRunningWords);
            Assert.AreEqual(1, measures.Paragraphs);
            Assert.AreEqual(1, measures.Sentences);

            ProjectOperations.RemoveProjectFile(file.RowId);

            rootDir = ProjectOperations.GetRootDirectory();
            measures = ProjectOperations.GetQuantitativeMeasures(rootDir.GetContextIncludedFiles());
            Assert.AreEqual(0, measures.TextLengthInRunningWords);
            Assert.AreEqual(0, measures.Paragraphs);
            Assert.AreEqual(0, measures.Sentences);
        }

        [TestMethod]
        public void ProjectOperationsTests_udf_pos_types_adding_and_removing_types()
        {
            var noun = ProjectOperations.AddPOSType("Noun", null);
            Assert.AreEqual("Noun", noun.Name);

            var mascNoun = ProjectOperations.AddPOSType("Masc Noun", noun);
            Assert.AreEqual("Masc Noun", mascNoun.Name);
            Assert.AreEqual(mascNoun.ParentPOSType, noun);
            Assert.AreEqual(mascNoun.ParentPOSTypeId, noun.RowId);
            Assert.AreEqual(noun.Children[0], mascNoun);

            var verb = ProjectOperations.AddPOSType("Verb", null);
            Assert.IsNotNull("Verb", verb.Name);

            var posTypes = ProjectOperations.GetPOSTypes();
            Assert.AreEqual(2, posTypes.Count);
            Assert.AreEqual("Noun", posTypes[0].Name);
            Assert.AreEqual("Masc Noun", posTypes[0].Children[0].Name);
            Assert.AreEqual("Verb", posTypes[1].Name);

            ProjectOperations.RemovePOSType(noun);
            posTypes = ProjectOperations.GetPOSTypes();
            Assert.AreEqual(1, posTypes.Count);
            Assert.AreEqual("Verb", posTypes[0].Name);

            ProjectOperations.RemovePOSType(verb);
            posTypes = ProjectOperations.GetPOSTypes();
            Assert.AreEqual(0, posTypes.Count);
        }

        [TestMethod]
        public void ProjectOperationsTests_udf_pos_types_parsing_posTypesText()
        {
            var text =
@"Noun
    Masc. Noun
    Fem. Noun
Verb
Adverb
    My Adverb
    My long long Adverb
Format
";
            var result = ProjectOperations.LoadPOSTypesFromText(text);
            Assert.AreEqual(4, result.Count);

            Assert.AreEqual("Noun", result[0].Name);
            Assert.AreEqual("Masc. Noun", result[0].Children[0].Name);
            Assert.AreEqual("Fem. Noun", result[0].Children[1].Name);
            Assert.AreEqual("Verb", result[1].Name);
            Assert.AreEqual("Adverb", result[2].Name);
            Assert.AreEqual("My Adverb", result[2].Children[0].Name);
            Assert.AreEqual("My long long Adverb", result[2].Children[1].Name);
            Assert.AreEqual("Format", result[3].Name);
        }

        [TestMethod]
        public void ProjectOperationsTests_udf_pos_types_serializing_posTypesTexts()
        {
            var types = new List<POSTypeModel> { 
                new POSTypeModel() { Name = "Noun" }, 
                new POSTypeModel() { Name = "Verb" },
                new POSTypeModel() { Name = "Adverb" },
                new POSTypeModel() { Name = "Format" },
            };
            types[0].Children.AddRange(new List<POSTypeModel>()
            {
                new POSTypeModel() { Name = "Masc. Noun" },
                new POSTypeModel() { Name = "Fem. Noun" },
            });
            types[2].Children.AddRange(new List<POSTypeModel>()
            {
                new POSTypeModel() { Name = "My Adverb" },
                new POSTypeModel() { Name = "My long long Adverb" },
            });

            var result = ProjectOperations.SerializePOSTypesToText(types);

            var text =
@"Noun
    Masc. Noun
    Fem. Noun
Verb
Adverb
    My Adverb
    My long long Adverb
Format
".Replace("    ", "\t");
            Assert.AreEqual(text, result);
        }

        [TestMethod]
        public void ProjectOperationsTests_udf_pos_types_get_pos_measures()
        {
            var file = TestUtility.CreateProcessedFile("some sentence with ten meaningless words sedem osem devet deset.");
            TestUtility.AddDefaultPOSTypes();
            var words = LemmatizerOperations.GetWords(file);
            var posTypes = ProjectOperations.GetPOSTypes();
            var noun = posTypes.Where(x => x.Name == "Noun").Single();
            var adver = posTypes.Where(x => x.Name == "Adverb").Single();

            POSTaggerOperations.AddPosTypeToWords(noun, words.Take(5));
            POSTaggerOperations.AddPosTypeToWords(adver, words.Skip(5).Take(5));

            var contextFiles = ProjectOperations.GetRootDirectory().GetContextIncludedFiles();
            posTypes = ProjectOperations.GetPOSTypesWithStatistics(contextFiles);
            noun = posTypes.Where(x => x.Name == "Noun").Single();
            adver = posTypes.Where(x => x.Name == "Adverb").Single();
            Assert.AreEqual(5, noun.Count);
            Assert.AreEqual(5, adver.Count);
        }

        [TestMethod]
        public void ProjectOperationsTests_context_on_by_default()
        {
            var file = TestUtility.CreateProcessedFile("some sentence with ten meaningless words sedem osem devet deset.");

            Assert.AreEqual(true, file.ContextIncluded);
        }

        [TestMethod]
        public void ProjectOperationsTests_context_exclude()
        {
            var file = TestUtility.CreateProcessedFile("some sentence with ten meaningless words sedem osem devet deset.");
            ProjectOperations.UpdateFileContextInclude(file.RowId, false);

            var rootDirectory = ProjectOperations.GetRootDirectory();

            Assert.AreEqual(false, rootDirectory.GetFiles()[0].ContextIncluded);
            Assert.AreEqual(0, rootDirectory.GetContextIncludedFiles().Count);
        }

        [TestMethod]
        public void BuildOperations_get_words_for_wordlist()
        {
            var sentence1 = @"Nqkakvo si izrechenie.";
            var sentence2 = @"Nqkakvo drugo izrechenie.";
            var text = string.Join(" ", sentence1, sentence2);
            var file = TestUtility.CreateProcessedFile(text);

            var words = WordListOperations.GetAllUniqueWords(file);

            Assert.AreEqual(4, words.Count);
            var Nqkakvo = GetWordByContent(words, "Nqkakvo");
            Assert.IsNotNull(Nqkakvo);
            Assert.AreEqual(2, Nqkakvo.Freq);

            var izrechenie = GetWordByContent(words, "izrechenie");
            Assert.IsNotNull(izrechenie);
            Assert.AreEqual(2, izrechenie.Freq);

            var si = GetWordByContent(words, "si");
            Assert.IsNotNull(si);
            Assert.AreEqual(1, si.Freq);

            var drugo = GetWordByContent(words, "drugo");
            Assert.IsNotNull(si);
            Assert.AreEqual(1, si.Freq);
        }

        #region Helpers

        private AggregatedWordModel GetWordByContent(IEnumerable<AggregatedWordModel> words, string content)
        {
            return words.Where(x => x.WordContent == content).FirstOrDefault();
        }

        #endregion
    }
}